package com.maple.p2pclient.p2m;

import android.media.MediaCodecInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import com.blankj.utilcode.util.DeviceUtils;
import com.maple.p2pclient.R;
import com.maple.p2pclient.app.Const;
import com.maple.p2pclient.core.PeerConnectionObserverAdapter;
import com.maple.p2pclient.core.SdpObserverAdapter;
import com.maple.p2pclient.socket.EventCode;
import com.maple.p2pclient.socket.MySocketIOClient;
import com.maple.p2pclient.socket.SocketCallbackAdapter;
import com.maple.p2pclient.socket.SocketType;
import com.maple.p2pclient.ui.MessageAdapter;
import com.maple.p2pclient.utils.LogUtils;
import com.maple.p2pclient.utils.WebRTCUtils;

import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.DefaultVideoDecoderFactory;
import org.webrtc.DefaultVideoEncoderFactory;
import org.webrtc.EglBase;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.RtpTransceiver;
import org.webrtc.SessionDescription;
import org.webrtc.SurfaceViewRenderer;
import org.webrtc.VideoEncoderSupportedCallback;
import org.webrtc.VideoTrack;

import java.util.ArrayList;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import static org.webrtc.DefaultVideoEncoderFactoryExtKt.createCustomVideoEncoderFactory;

public class P2MAppActivity extends AppCompatActivity {

    private String userId;

    private ListView lvList;
    private TextView tvState;
    private Button btnStart;


    private SurfaceViewRenderer remoteRenderer;

    private PeerConnectionFactory peerConnectionFactory;
    private PeerConnection peerConnection;

    private EglBase.Context eglBaseContext = EglBase.create().getEglBaseContext();

    private MySocketIOClient socketClient;


    private SocketCallbackAdapter socketCallback = new SocketCallbackAdapter() {
        @Override
        public void onConnected() {
            super.onConnected();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    tvState.setText("已连接");
                    addItemList("已连接");
                }
            });
        }

        @Override
        public void onDisconnect() {
            super.onDisconnect();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    addItemList("断开连接");
                }
            });
        }

        @Override
        public void onConnectError(String error) {
            super.onConnectError(error);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    addItemList(error);
                }
            });
        }

        @Override
        public void onOffer(JSONObject json) {
            super.onOffer(json);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    try {
                        addItemList(json.toString());

                        String user = json.getString("user");
                        if(!userId.equals(user)) {
                            return;
                        }
                        String form = json.getString("form");
                        String to = json.getString("to");
                        if(form.equals(SocketType.CAMERA.getType()) && to.equals(SocketType.APP.getType())) {
                            // answer 发送 sdp 给 camera
                            createAnswer(json);
                        }
                    } catch (JSONException e) {
                        LogUtils.logGGQ("onOffer ERROR:" + e.getMessage());
                    }
                }
            });
        }


        @Override
        public void onException(String error) {
            super.onException(error);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    addItemList(error);
                }
            });
        }

        @Override
        public void onEvent(JSONObject json) {
            super.onEvent(json);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    addItemList(json.toString());
                }
            });
        }
    };

    private MessageAdapter listAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_p2m_app);
        tvState = findViewById(R.id.tv_state);
        lvList = findViewById(R.id.lv_list);
        btnStart = findViewById(R.id.btn_start);
        remoteRenderer = findViewById(R.id.svr_remote_renderer);
        remoteRenderer.init(eglBaseContext,null);
        remoteRenderer.setMirror(false);

        userId = DeviceUtils.getAndroidID();
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(socketClient.isConnected()) {
                    try {
                        JSONObject json = new JSONObject();
                        json.put("code", EventCode.JOIN.getCode());
                        json.put("type",SocketType.APP.getType());
                        json.put("user",userId);
                        json.put("message",userId + " 加入");
                        socketClient.sendEvent("event",json);
                    } catch (JSONException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });

        listAdapter = new MessageAdapter(this,new ArrayList<String>());
        lvList.setAdapter(listAdapter);

        socketClient = new MySocketIOClient();
        socketClient.setToken(SocketType.APP.getType());
        socketClient.setCallback(socketCallback);
        socketClient.connect(Const.SOCKET_URL);
        initRTC();
    }

    private void initRTC() {
        PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
        DefaultVideoEncoderFactory encoderFactory = createCustomVideoEncoderFactory(eglBaseContext, true, true, new VideoEncoderSupportedCallback() {
            @Override
            public boolean isSupportedH264(@NonNull MediaCodecInfo info) {
                return true;
            }
        });

        DefaultVideoDecoderFactory decoderFactory = new DefaultVideoDecoderFactory(eglBaseContext);
        peerConnectionFactory = PeerConnectionFactory
                .builder()
                .setOptions(options)
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory)
                .createPeerConnectionFactory();

        PeerConnection.RTCConfiguration rtcConfig = WebRTCUtils.createRTCConfiguration();
        rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;

        peerConnection = peerConnectionFactory.createPeerConnection(rtcConfig,new PeerConnectionObserverAdapter(SocketType.APP.getType()){

            @Override
            public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {
                super.onIceConnectionChange(iceConnectionState);
                LogUtils.logGGQ("app onIceConnectionChange");
            }

            @Override
            public void onIceCandidate(IceCandidate iceCandidate) {
                super.onIceCandidate(iceCandidate);
                if(socketClient != null) {
                    // 回调 onIceCandidate
                    socketClient.sendIceCandidate(SocketType.APP,SocketType.CAMERA,userId,iceCandidate);
                }
            }

            @Override
            public void onTrack(RtpTransceiver transceiver) {
                super.onTrack(transceiver);
                // 回调
                if (transceiver != null && transceiver.getReceiver().track() instanceof VideoTrack) {
                    VideoTrack videoTrack = (VideoTrack) transceiver.getReceiver().track();
                    if(videoTrack != null) {
                        videoTrack.addSink(remoteRenderer);
                    }
                }
            }
        });
    }
    private void createAnswer(JSONObject json) {
        if(peerConnection != null) {
            try {
                // 远端接收到的SDP描述字符串
                String description = json.getString("sdp");
                // 将接收到的SDP描述解析为SessionDescription对象
                SessionDescription offer = new SessionDescription(SessionDescription.Type.OFFER, description);
                // 设置远端描述
                peerConnection.setRemoteDescription(new SdpObserverAdapter("setRemoteDescription") {
                    @Override
                    public void onSetSuccess() {
                        super.onSetSuccess();
                        // 远端描述设置成功，接下来可以创建和发送答案
                        peerConnection.createAnswer(new SdpObserverAdapter("createAnswer") {
                            @Override
                            public void onCreateSuccess(SessionDescription sdp) {
                                super.onCreateSuccess(sdp);
                                if (sdp != null && sdp.type == SessionDescription.Type.ANSWER) {
                                    peerConnection.setLocalDescription(new SdpObserverAdapter("setLocalDescription") {
                                        @Override
                                        public void onSetSuccess() {
                                            super.onSetSuccess();
                                            // 将 SDP Answer 发送回发起端
                                            if (socketClient != null) {
                                                socketClient.sendAnswer(SocketType.APP, SocketType.CAMERA, userId,sdp);
                                            }
                                        }
                                    },sdp);
                                }
                            }
                        }, new MediaConstraints());
                    }
                },offer);
            } catch (JSONException e) {
                LogUtils.logGGQ("createAnswer ERROR:" + e.getMessage());
            }
        }
    }

    private void addItemList(String item) {
        listAdapter.addItem(item);
        lvList.smoothScrollToPosition(listAdapter.getDataList().size() - 1);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(socketClient != null) {
            socketClient.close();
        }
        if(remoteRenderer != null) {
            remoteRenderer.release();
        }
        if(peerConnection != null) {
            peerConnection.dispose();
        }
        if(peerConnectionFactory != null) {
            peerConnectionFactory.dispose();
        }
    }
}